#pragma once
#include <semaphore.h>
#include <pthread.h>
#include <vector>
#include "LockGuard.hpp"

const int defaultsize = 5;
template<class T>
class RingQueue
{
private:
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
public:
    RingQueue(int size = defaultsize)
    :_ringqueue(size), _size(size),_step_p(0), _step_c(0)
    {
        sem_init(&_sem_p, 0, _size); //第二参数是0，表示的线程的信号量
        sem_init(&_sem_c, 0, 0);

        pthread_mutex_init(&_mutex_p, nullptr);
        pthread_mutex_init(&_mutex_c, nullptr);
    }

    void Push(const T& task) //productor
    {
        P(_sem_p);
        {
            // pthread_mutex_lock(&_mutex_p);
            LockGuard lock(&_mutex_p);
            _ringqueue[_step_p++] = task;
            _step_p %= _size;
            // pthread_mutex_unlock(&_mutex_p);
        }
        V(_sem_c);
    }
    void Pop(T* out)
    {
        P(_sem_c);
        {
            // pthread_mutex_lock(&_mutex_c);
            LockGuard lock(&_mutex_p);
            *out = _ringqueue[_step_c++];
            _step_c %= _size;
            // pthread_mutex_unlock(&_mutex_c);
        }
        V(_sem_p);
    }
private:
    std::vector<T> _ringqueue;
    int _size;

    int _step_p;
    int _step_c;

    sem_t _sem_p;
    sem_t _sem_c;

    pthread_mutex_t _mutex_p;
    pthread_mutex_t _mutex_c;
};